/*
 * Copyright (c) 2005-2006 Rincon Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Rincon Research Corporation nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE
 */
 
#include "Timer.h"
#include "RssiToSerial.h"
#include "msp430usart.h"
#include "printf.h"
 
 /**
  * This is more of a general demonstration than a test.
  *
  * Install this application to one node, connected to the computer.
  * The node will measure the environmental RSSI from the CC2420 and
  * sending those readings over the serial port.
  *
  * Use the Java application to display the relative RSSI readings.
  *
  * @author Jared Hill
 * @date   23 March 2007
  */
uint8_t samples[6000]; 
uint32_t startTime = 0;
uint32_t endTime = 0;
module RssiToSerialP {
  uses {
    interface Leds;
    interface Boot;
    interface AMSend;
    interface SplitControl as AMControl;
    interface SplitControl as SerialControl;
    interface Packet;
    interface Read<uint16_t> as ReadRssi;
    interface CC2420Config as Config;

	interface Timer<TMilli> as SerialTimer;
  }
}
implementation {

  /******* Global Variables ****************/
  message_t packet;
  bool locked;
  uint32_t total;
  uint16_t largest;
  uint16_t reads;

	//uint8_t samples[6000];
	uint16_t sampleNum = 0;
	uint16_t packetNum = 0;
	uint16_t index = 0;
	uint16_t NoSample = 0;
	uint8_t timerCounter = 0;
	uint8_t firstF = 2;

	bool sampleFlag = TRUE;
  
  /******** Declare Tasks *******************/
  task void readRssi();
  task void sendSerialMsg();
    static inline void split_write(uint8_t val);
  static inline uint8_t split_read();
  static inline uint8_t split_read_write(uint8_t val);
  
  /************ Boot Events *****************/
  event void Boot.booted() {
    call AMControl.start();
    total = 0;
    largest = 0;
    reads = 0;
    locked = FALSE;
    NoSample = 0;
  }

  /************ AMControl Events ******************/
  event void AMControl.startDone(error_t err) {
    if (err == SUCCESS) {
    
      call SerialControl.start();
      
    }
    else {
      call AMControl.start();
    }
  }

  event void AMControl.stopDone(error_t err) {
    // do nothing
  }

  static inline void set_mode_spi(msp430_spi_union_config_t* config) {
    atomic {
      U0CTL = SWRST;                     // reset USART
      ME1 &= ~(UTXE0 | URXE0);           // disable USRT Module
      P3SEL &= ~(0x01 << 4);             // UTXD
      P3SEL &= ~(0x01 << 5);             // URXD
      // configure the SPI parameters
      U0CTL = (config->spiRegisters.uctl) | SYNC | SWRST;
      U0TCTL = config->spiRegisters.utctl;
      U0BR0 = (config->spiRegisters.ubr) & 0x00FF;
      U0BR1 = ((config->spiRegisters.ubr) >> 8) & 0x00FF;
      U0MCTL = 0x00;
      // select module function
      P3SEL |= (0x01 << 1);
      P3SEL |= (0x01 << 2);
      P3SEL |= (0x01 << 3);
      ME1 |= USPIE0;
      U0CTL &= ~SWRST;
      IFG1 &= ~(UTXIFG0 | URXIFG0);
      IE1 &= ~(UTXIE0 | URXIE0);
    }
  }

	void initiation() {
		int i =0;
		for(;i<6000;i++) {
			samples[i] = 0;
		}	
		//call Leds.led1On();
		 set_mode_spi(&msp430_spi_default_config);
	}
  
  /***************SerialControl Events*****************/
  event void SerialControl.startDone(error_t error){
    if (error == SUCCESS) {
    	
	initiation();
	call SerialTimer.startOneShot(3000);
	
	//call SerialTimer.startPeriodic(1);
      post readRssi();
    }
    else {
      call AMControl.start();
    }
  }
  
  event void SerialControl.stopDone(error_t error){
    //do nothing
  }
  
  /***************** AMSend Events ****************************/
  event void AMSend.sendDone(message_t* bufPtr, error_t error) {
    
    call Leds.led2Toggle();
    if (&packet == bufPtr) {
      locked = FALSE;
      	//call Leds.led1Off();
    
	index++;
	if(NoSample<SAMPLE_NUMBER){
		post sendSerialMsg();
	}
	
    }
    //post readRssi();
  }
  
  /**************** ReadRssi Events *************************/
  event void ReadRssi.readDone(error_t result, uint16_t val ){

	uint8_t temp;
    
    if(result != SUCCESS){
      post readRssi();
      return;
    }
  }

	event void SerialTimer.fired() {
		//call Leds.led0On();
		post sendSerialMsg();
	}
  
  /********************* Config Events *************************/
  event void Config.syncDone(error_t error){
  
  }

  /***************** TASKS *****************************/  
  task void readRssi(){
  uint16_t i = 0;
  uint8_t addr = 0;

  addr = 0x13 | 0x40;
/*
    for ( ; i<6000; i++) {
      P4OUT |= (1 << 2);
    P4OUT &= ~(1 << 2);
    U0TXBUF = addr;
     while ( !(IFG1 & URXIFG0) );
    samples[i] = U0RXBUF;
    }
    */


    P4OUT |= (1 << 2);
    P4OUT &= ~(1 << 2);
	startTime = call SerialTimer.getNow();
    split_write( addr );
    //split_read_write( addr );

    for ( ; i<6000-1; i++) {
    split_read_write( 0 ); 		//reading the return value of split_write(addr)
    split_read_write( 0 );		//reading the high 8 bits
     samples[i]=split_read_write( addr );		//reading the low 8 bits and write addr to bus.
    }

    samples[i]=split_read();
    
	endTime = call SerialTimer.getNow();
    P4OUT |= (1 << 2);

  }


  static inline void split_write(uint8_t val) {
    U0TXBUF = val;
  }

  static inline uint8_t split_read() {
    while ( !(IFG1 & URXIFG0) );
    return U0RXBUF;
  }

  static inline uint8_t split_read_write(uint8_t val) {
    uint8_t tmp;

    while ( !(IFG1 & URXIFG0) ){}; //when other nodes sending packets, it loops here when i==2.
    tmp = U0RXBUF;

    while ( !(IFG1 & UTXIFG0) );
    U0TXBUF = val;

    return tmp;
  }



  
  task void sendSerialMsg(){

    if(locked){
      return;
    }
    else {
      rssi_serial_msg_t* rsm = (rssi_serial_msg_t*)call Packet.getPayload(&packet, sizeof(rssi_serial_msg_t));
      
      if (call Packet.maxPayloadLength() < sizeof(rssi_serial_msg_t)) {
	    return;
      }
	  atomic{
	    //rsm->rssiAvgValue = (total >> (LOG2SAMPLES));
	    //rsm->rssiLargestValue = largest;
	  }
		if(firstF == 2){
			rsm->rssiAvgValue = startTime;
			firstF--;
		}
		else if(firstF == 1) {
			rsm->rssiAvgValue = endTime;
			firstF--;
		}
		else {
			rsm->rssiAvgValue = samples[NoSample++];
			rsm->rssiLargestValue = samples[NoSample++];
		}
	      rsm->channel = call Config.getChannel();
	      //call Leds.led1On();
	      if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rssi_serial_msg_t)) == SUCCESS) {
		    locked = TRUE;
	      }

    }
  
/*
	call Leds.led0On();
	printf("%lu, %lu\n",startTime, endTime);
	printfflush();
	for(NoSample = 0;NoSample<5000;) {
		//printf("%u \t %u\n", NoSample, samples[NoSample++]);
		printf("%u\n", samples[NoSample++]);
		printfflush();
		
	}

	//printfflush();
	call Leds.led2On();
*/
  }
 }




